<!doctype html><html lang=zh-hans>
<head>
<meta charset=utf-8>
<meta name=viewport content="width=device-width,initial-scale=1">
<meta http-equiv=x-ua-compatible content="IE=edge">
<meta name=author content="小李刀刀">
<meta name=description content="首先，如果需要了解手动编写原生查询语句，可以阅读(/docs/database/access/)。 DBAL 组件包含了一系列查询构造器，用于统一不同数据库的语法。并在应用程序的生命周期内简化在不同种类的数据库之间进行数据迁移。 开始之前 为了演示组件的查询构造能力，我们首先在默认数据库定义一">
<meta name=theme-color content="#3f51b5">
<link rel=stylesheet href=https://cdnjs.cloudflare.com/ajax/libs/academicons/1.8.6/css/academicons.min.css integrity="sha256-uFVgMKfistnJAfoCUQigIl+JfUaP47GrRKjf6CTPVmw=" crossorigin=anonymous>
<link rel=stylesheet href=https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.12.0-1/css/all.min.css integrity="sha256-4w9DunooKSr3MFXHXWyFER38WmPdm361bQS/2KUWZbU=" crossorigin=anonymous>
<link rel=stylesheet href=https://cdnjs.cloudflare.com/ajax/libs/fancybox/3.5.7/jquery.fancybox.min.css integrity="sha256-Vzbj7sDDS/woiFS3uNKo8eIuni59rjyNGtXfstRzStA=" crossorigin=anonymous>
<link rel=stylesheet href=https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.18.1/styles/tomorrow-night.min.css crossorigin=anonymous title=hl-light>
<link rel=stylesheet href=https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.18.1/styles/tomorrow-night.min.css crossorigin=anonymous title=hl-dark disabled>
<script src=https://cdnjs.cloudflare.com/ajax/libs/lazysizes/5.1.2/lazysizes.min.js integrity="sha256-Md1qLToewPeKjfAHU1zyPwOutccPAm5tahnaw7Osw0A=" crossorigin=anonymous async></script>
<link rel=stylesheet href="https://fonts.font.im/css?family=Source+Code+Pro:300,400,500,600,700&subset=latin-ext&display=swap">
<link rel=stylesheet href=/css/academic.css>
<script>(function(b,d,e,a,g){b[a]=b[a]||[],b[a].push({'gtm.start':(new Date).getTime(),event:'gtm.js'});var f=d.getElementsByTagName(e)[0],c=d.createElement(e),h=a!='dataLayer'?'&l='+a:'';c.async=!0,c.src='https://www.googletagmanager.com/gtm.js?id='+g+h,f.parentNode.insertBefore(c,f)})(window,document,'script','dataLayer','GTM-5KZH8N7')</script>
<link rel=manifest href=/index.webmanifest>
<link rel=icon type=image/png href=/images/icon_hu0b7a4cb9992c9ac0e91bd28ffd38dd00_9727_32x32_fill_lanczos_center_3.png>
<link rel=apple-touch-icon type=image/png href=/images/icon_hu0b7a4cb9992c9ac0e91bd28ffd38dd00_9727_192x192_fill_lanczos_center_3.png>
<link rel=canonical href=https://studyspiral.cn/docs/database/query-builders/>
<meta property="twitter:card" content="summary">
<meta property="og:site_name" content="Spiral中文网">
<meta property="og:url" content="https://studyspiral.cn/docs/database/query-builders/">
<meta property="og:title" content="查询构造器 | Spiral中文网">
<meta property="og:description" content="首先，如果需要了解手动编写原生查询语句，可以阅读(/docs/database/access/)。 DBAL 组件包含了一系列查询构造器，用于统一不同数据库的语法。并在应用程序的生命周期内简化在不同种类的数据库之间进行数据迁移。 开始之前 为了演示组件的查询构造能力，我们首先在默认数据库定义一"><meta property="og:image" content="https://studyspiral.cn/images/logo.svg">
<meta property="twitter:image" content="https://studyspiral.cn/images/logo.svg"><meta property="og:locale" content="zh-Hans">
<meta property="article:published_time" content="2020-04-28T23:21:46+08:00">
<meta property="article:modified_time" content="2020-08-28T15:38:18+08:00">
<script src=https://cdnjs.cloudflare.com/ajax/libs/cookieconsent2/3.1.1/cookieconsent.min.js integrity="sha256-5VhCqFam2Cn+yjw61zbBNrbHVJ6SRydPeKopYlngbiQ=" crossorigin=anonymous></script>
<link rel=stylesheet href=https://cdnjs.cloudflare.com/ajax/libs/cookieconsent2/3.1.1/cookieconsent.min.css integrity="sha256-zQ0LblD/Af8vOppw18+2anxsuaz3pWYyVWi+bTvTH8Q=" crossorigin=anonymous>
<script>window.addEventListener("load",function(){window.cookieconsent.initialise({palette:{popup:{background:"#3f51b5",text:"#fff"},button:{background:"#fff",text:"#3f51b5"}},theme:"classic",content:{message:"本网站使用cookies来确保您在本网站上获得最佳体验。",dismiss:"知道了!",link:"了解更多",href:"https://www.cookiesandyou.com"}})})</script>
<title>查询构造器 | Spiral中文网</title>
</head>
<body id=top data-spy=scroll data-offset=70 data-target=#TableOfContents>
<aside class=search-results id=search>
<div class=container>
<section class=search-header>
<div class="row no-gutters justify-content-between mb-3">
<div class=col-6>
<h1>搜索</h1>
</div>
<div class="col-6 col-search-close">
<a class=js-search href=#><i class="fas fa-times-circle text-muted" aria-hidden=true></i></a>
</div>
</div>
<div id=search-box>
<input name=q id=search-query placeholder=搜索... autocapitalize=off autocomplete=off autocorrect=off spellcheck=false type=search>
</div>
</section>
<section class=section-search-results>
<div id=search-hits>
</div>
</section>
</div>
</aside>
<nav class="navbar navbar-expand-lg navbar-light compensate-for-scrollbar" id=navbar-main>
<div class=container>
<div class="d-none d-lg-inline-flex">
<a class=navbar-brand href=/><img src=/images/logo.svg alt=Spiral中文网>Spiral中文网</a>
</div>
<button type=button class=navbar-toggler data-toggle=collapse data-target=#navbar-content aria-controls=navbar aria-expanded=false aria-label=切换导航>
<span><i class="fas fa-bars"></i></span>
</button>
<div class="navbar-brand-mobile-wrapper d-inline-flex d-lg-none">
<a class=navbar-brand href=/><img src=/images/logo.svg alt=Spiral中文网>Spiral中文网</a>
</div>
<div class="navbar-collapse main-menu-item collapse justify-content-end" id=navbar-content>
<ul class="navbar-nav d-md-inline-flex">
<li class=nav-item>
<a class=nav-link href=/docs/basics/quick-start/><span>教程</span></a>
</li>
<li class=nav-item>
<a class="nav-link active" href=/docs/><span>文档</span></a>
</li>
<li class=nav-item>
<a class=nav-link href=/post/><span>文章</span></a>
</li>
</ul>
</div>
<ul class="nav-icons navbar-nav flex-row ml-auto d-flex pl-md-2">
<li class=nav-item>
<a class="nav-link js-search" href=#><i class="fas fa-search" aria-hidden=true></i></a>
</li>
</ul>
</div>
</nav>
<div class="container-fluid docs">
<div class="row flex-xl-nowrap">
<div class="col-12 col-md-3 col-xl-2 docs-sidebar">
<form class="docs-search d-flex align-items-center">
<button class="btn docs-toggle d-md-none p-0 mr-3" type=button data-toggle=collapse data-target=#docs-nav aria-controls=docs-nav aria-expanded=false aria-label="Toggle section navigation">
<span><i class="fas fa-bars"></i></span>
</button>
<input name=q type=search class=form-control placeholder=搜索... autocomplete=off>
</form>
<nav class="collapse docs-links" id=docs-nav>
<div class=docs-toc-item>
<a class=docs-toc-link href=/docs/extension/dotenv/>Dotenv</a>
</div>
<div class=docs-toc-item>
<a class=docs-toc-link href=/docs/>总览</a>
<ul class="nav docs-sidenav docs-sidenav-sub collapse show">
<li>
<a href=/docs/>Spiral介绍</a>
</li>
<li>
<a href=/docs/about/contributing/>贡献指引</a>
</li>
<li>
<a href=/docs/about/semver/>版本说明</a>
</li>
<li>
<a href=/docs/about/license/>授权协议</a>
</li>
</ul>
</div>
<div class=docs-toc-item>
<a class=docs-toc-link href=/docs/http/psr-15/>定制 PSR-15 处理器</a>
</div>
<div class=docs-toc-item>
<a class=docs-toc-link href=/docs/start/install/>快速开始</a>
<ul class="nav docs-sidenav docs-sidenav-sub collapse">
<li>
<a href=/docs/start/install/>安装指引</a>
</li>
<li>
<a href=/docs/start/workers/>应用工作进程</a>
</li>
<li>
<a href=/docs/start/structure/>应用程序结构</a>
</li>
<li>
<a href=/docs/start/configuration/>默认配置</a>
</li>
<li>
<a href=/docs/start/commands/>控制台命令</a>
</li>
</ul>
</div>
<div class=docs-toc-item>
<a class=docs-toc-link href=/docs/basics/quick-start/>入门基础</a>
<ul class="nav docs-sidenav docs-sidenav-sub collapse">
<li>
<a href=/docs/basics/quick-start/>上手指南</a>
</li>
<li>
<a href=/docs/basics/scaffolding/>脚手架</a>
</li>
<li>
<a href=/docs/basics/prototype/>原型开发辅助</a>
</li>
</ul>
</div>
<div class=docs-toc-item>
<a class=docs-toc-link href=/docs/framework/design/>核心框架</a>
<ul class="nav docs-sidenav docs-sidenav-sub collapse">
<li>
<a href=/docs/framework/design/>设计理念</a>
</li>
<li>
<a href=/docs/framework/application-server/>应用服务器</a>
</li>
<li>
<a href=/docs/framework/config/>配置对象</a>
</li>
<li>
<a href=/docs/framework/kernel/>内核与环境</a>
</li>
<li>
<a href=/docs/framework/container/>容器</a>
</li>
<li>
<a href=/docs/framework/bootloaders/>引导程序</a>
</li>
<li>
<a href=/docs/framework/scopes/>IoC 作用域</a>
</li>
<li>
<a href=/docs/framework/memory/>静态高速缓存</a>
</li>
<li>
<a href=/docs/framework/finalizers/>终结器</a>
</li>
</ul>
</div>
<div class=docs-toc-item>
<a class=docs-toc-link href=/docs/cookbook/annotated-routes/>速查手册</a>
<ul class="nav docs-sidenav docs-sidenav-sub collapse">
<li>
<a href=/docs/cookbook/annotated-routes/>注解式路由</a>
</li>
<li>
<a href=/docs/cookbook/injector/>容器注入器</a>
</li>
<li>
<a href=/docs/cookbook/domain-core/>领域内核、控制器</a>
</li>
<li>
<a href=/docs/cookbook/golang-library/>Golang服务集成</a>
</li>
<li>
<a href=/docs/cookbook/custom-dispatcher/>自定义调度器</a>
</li>
</ul>
</div>
<div class=docs-toc-item>
<a class=docs-toc-link href=/docs/component/files/>常用组件</a>
<ul class="nav docs-sidenav docs-sidenav-sub collapse">
<li>
<a href=/docs/component/files/>文件和目录</a>
</li>
<li>
<a href=/docs/component/reactor/>代码生成</a>
</li>
<li>
<a href=/docs/component/tokenizer/>静态分析工具</a>
</li>
<li>
<a href=/docs/component/metrics/>应用指标</a>
</li>
<li>
<a href=/docs/component/data-grid/>数据网格</a>
</li>
</ul>
</div>
<div class=docs-toc-item>
<a class=docs-toc-link href=/docs/console/configuration/>控制台</a>
<ul class="nav docs-sidenav docs-sidenav-sub collapse">
<li>
<a href=/docs/console/configuration/>安装和配置</a>
</li>
<li>
<a href=/docs/console/commands/>用户命令</a>
</li>
</ul>
</div>
<div class=docs-toc-item>
<a class=docs-toc-link href=/docs/http/configuration/>HTTP</a>
<ul class="nav docs-sidenav docs-sidenav-sub collapse">
<li>
<a href=/docs/http/configuration/>安装配置</a>
</li>
<li>
<a href=/docs/http/lifecycle/>请求生命周期</a>
</li>
<li>
<a href=/docs/http/request-response/>请求和响应</a>
</li>
<li>
<a href=/docs/http/routing/>路由</a>
</li>
<li>
<a href=/docs/http/errors/>错误页面</a>
</li>
<li>
<a href=/docs/http/middleware/>中间件</a>
</li>
<li>
<a href=/docs/http/golang/>Golang 中间件</a>
</li>
<li>
<a href=/docs/http/cookies/>Cookies</a>
</li>
<li>
<a href=/docs/http/session/>Session</a>
</li>
<li>
<a href=/docs/http/csrf/>CSRF 防护</a>
</li>
</ul>
</div>
<div class=docs-toc-item>
<a class=docs-toc-link href=/docs/security/encrypter/>安全</a>
<ul class="nav docs-sidenav docs-sidenav-sub collapse">
<li>
<a href=/docs/security/encrypter/>数据加密</a>
</li>
<li>
<a href=/docs/security/validation/>数据验证</a>
</li>
<li>
<a href=/docs/security/rbac/>基于角色的权限控制</a>
</li>
<li>
<a href=/docs/security/authentication/>用户认证</a>
</li>
</ul>
</div>
<div class=docs-toc-item>
<a class=docs-toc-link href=/docs/filters/configuration/>请求过滤</a>
<ul class="nav docs-sidenav docs-sidenav-sub collapse">
<li>
<a href=/docs/filters/configuration/>安装和配置</a>
</li>
<li>
<a href=/docs/filters/filter/>过滤器</a>
</li>
<li>
<a href=/docs/filters/composite/>复合过滤器</a>
</li>
</ul>
</div>
<div class=docs-toc-item>
<a class=docs-toc-link href=/docs/database/configuration/>数据库</a>
<ul class="nav docs-sidenav docs-sidenav-sub collapse show">
<li>
<a href=/docs/database/configuration/>安装与配置</a>
</li>
<li>
<a href=/docs/database/access/>访问数据</a>
</li>
<li>
<a href=/docs/database/isolation/>逻辑隔离</a>
</li>
<li class=active>
<a href=/docs/database/query-builders/>查询构造器</a>
</li>
<li>
<a href=/docs/database/transactions/>Transactions</a>
</li>
<li>
<a href=/docs/database/introspection/>Schema Introspection</a>
</li>
<li>
<a href=/docs/database/declaration/>Declaration</a>
</li>
<li>
<a href=/docs/database/migrations/>Migrations</a>
</li>
<li>
<a href=/docs/database/errata/>Errata</a>
</li>
</ul>
</div>
<div class=docs-toc-item>
<a class=docs-toc-link href=/docs/cycle/configuration/>Cycle ORM</a>
<ul class="nav docs-sidenav docs-sidenav-sub collapse">
<li>
<a href=/docs/cycle/configuration/>Configuration</a>
</li>
</ul>
</div>
<div class=docs-toc-item>
<a class=docs-toc-link href=/docs/queue/configuration/>队列任务</a>
<ul class="nav docs-sidenav docs-sidenav-sub collapse">
<li>
<a href=/docs/queue/configuration/>Configuration</a>
</li>
<li>
<a href=/docs/queue/scraper/>网站爬虫</a>
</li>
</ul>
</div>
<div class=docs-toc-item>
<a class=docs-toc-link href=/docs/views/configuration/>视图</a>
<ul class="nav docs-sidenav docs-sidenav-sub collapse">
<li>
<a href=/docs/views/configuration/>Configuration</a>
</li>
</ul>
</div>
<div class=docs-toc-item>
<a class=docs-toc-link href=/docs/stempler/configuration/>Stempler 模板</a>
<ul class="nav docs-sidenav docs-sidenav-sub collapse">
<li>
<a href=/docs/stempler/configuration/>Configuration</a>
</li>
<li>
<a href=/docs/stempler/directives/>Directives</a>
</li>
</ul>
</div>
<div class=docs-toc-item>
<a class=docs-toc-link>国际化</a>
</div>
<div class=docs-toc-item>
<a class=docs-toc-link>GRPC</a>
</div>
<div class=docs-toc-item>
<a class=docs-toc-link>事件广播</a>
</div>
<div class=docs-toc-item>
<a class=docs-toc-link>调试及性能</a>
</div>
<div class=docs-toc-item>
<a class=docs-toc-link>扩展</a>
</div>
</nav>
</div>
<div class="d-none d-xl-block col-xl-2 docs-toc">
<ul class="nav toc-top">
<li><a href=# id=back_to_top class=docs-toc-title>在本页</a></li>
</ul>
<nav id=TableOfContents>
<ul>
<li><a href=#开始之前>开始之前</a></li>
<li><a href=#插入语句>插入语句</a>
<ul>
<li><a href=#批量插入>批量插入</a></li>
<li><a href=#快速插入>快速插入</a></li>
</ul>
</li>
<li><a href=#select-查询构造器>select 查询构造器</a>
<ul>
<li><a href=#查询字段>查询字段</a></li>
<li><a href=#where-语句>Where 语句</a></li>
<li><a href=#表和字段别名>表和字段别名</a></li>
<li><a href=#having>Having</a></li>
<li><a href=#联合查询>联合查询</a></li>
<li><a href=#排序>排序</a></li>
<li><a href=#分组和去重>分组和去重</a></li>
<li><a href=#聚合和计数>聚合和计数</a></li>
<li><a href=#分页>分页</a></li>
</ul>
</li>
<li><a href=#更新查询构造器>更新查询构造器</a></li>
<li><a href=#删除查询构造器>删除查询构造器</a></li>
<li><a href=#复杂表达式>复杂表达式</a></li>
</ul>
</nav>
</div>
<main class="col-12 col-md-9 col-xl-8 py-md-3 pl-md-5 docs-content" role=main>
<article class=article>
<div class="alert alert-warning" role=alert>
官方文档中文版翻译工作仍在进行中，欢迎 <a href=/post/join-translation/>参与翻译</a>。
</div>
<div class=docs-article-container>
<h1>查询构造器</h1>
<div class=article-style>
<p>首先，如果需要了解手动编写原生查询语句，可以阅读(/docs/database/access/)。</p>
<p>DBAL 组件包含了一系列查询构造器，用于统一不同数据库的语法。并在应用程序的生命周期内简化在不同种类的数据库之间进行数据迁移。</p>
<h2 id=开始之前>开始之前</h2>
<p>为了演示组件的查询构造能力，我们首先在默认数据库定义一个简单的的数据表：</p>
<pre><code class=language-php>namespace App\Controller;

use Spiral\Database\Database;

class HomeController
{
    public function index(Database $db)
    {
        $schema = $db-&gt;table('test')-&gt;getSchema();

        $schema-&gt;primary('id');
        $schema-&gt;datetime('time_created');
        $schema-&gt;enum('status', ['active', 'disabled'])-&gt;defaultValue('active');
        $schema-&gt;string('name', 64);
        $schema-&gt;string('email');
        $schema-&gt;double('balance');
        $schema-&gt;save();
    }
}
</code></pre>
<blockquote>
<p>更多有关数据库结构声明的介绍，请参阅(/docs/database/declaration/)。</p>
</blockquote>
<h2 id=插入语句>插入语句</h2>
<p>我们可以用以下的代码来获得一个插入语句构造器（负责插入操作）：</p>
<pre><code class=language-php>$insert = $db-&gt;insert('test');
</code></pre>
<p>然后给插入语句构造器添加字段的具体值用于插入数据到指定的表：</p>
<pre><code class=language-php>$insert = $db-&gt;insert('test');

$insert-&gt;values([
    'time_created' =&gt; new \DateTime(),
    'name'         =&gt; 'Anton',
    'email'        =&gt; 'test@email.com',
    'balance'      =&gt; 800.90
]);
</code></pre>
<p>定义完成后，要正式执行插入查询，只要执行 <code>run()</code> 方法即可，该方法会返回最后插入记录的 id:</p>
<pre><code class=language-php>dump($db-&gt;run());
</code></pre>
<blockquote>
<p>你也可以使用更流利的链式语法：<code>$database->insert('table')->values(...)->run()</code>.</p>
</blockquote>
<h3 id=批量插入>批量插入</h3>
<p>如果需要批量插入多条记录，可以添加数据库支持一次性插入的任意数量的值：</p>
<pre><code class=language-php>$insert-&gt;columns([
    'time_created', 
    'name', 
    'email', 
    'balance'
]);

for ($i = 0; $i &lt; 20; $i++) {
    // 前面已经指定了字段，这里只需要提供值即可
    $insert-&gt;values([
        new \DateTime(),
        $this-&gt;faker-&gt;randomNumber(2),
        $this-&gt;faker-&gt;email,
        $this-&gt;faker-&gt;randomFloat(2)
    ]);
}

$insert-&gt;run();
</code></pre>
<h3 id=快速插入>快速插入</h3>
<p>还可以跳过插入构造器的创建过程，直接与数据表对话：</p>
<pre><code class=language-php>$table = $db-&gt;table('test');

dump($table-&gt;insertOne([
    'time_created' =&gt; new \DateTime(),
    'name'         =&gt; 'Anton',
    'email'        =&gt; 'test@email.com',
    'balance'      =&gt; 800.90
]));
</code></pre>
<blockquote>
<p>Table 类会自动执行查询并返回最新插入的记录的 id. 可以自行了解 Table 类的 <code>insertMultiple</code> 方法。</p>
</blockquote>
<h2 id=select-查询构造器>select 查询构造器</h2>
<p>Select 查询构造器实例可以通过两种非常简单的方式获取，一种是从数据库实例，一种是从数据表实例：</p>
<pre><code class=language-php>$select = $db-&gt;table('test')-&gt;select();

// 另一种方法
$select = $db-&gt;select()-&gt;from('test');

// 另一种方法
$select = $db-&gt;test-&gt;select();
</code></pre>
<h3 id=查询字段>查询字段</h3>
<p>默认情况下，Select 查询会从指定表中选择所有字段（<code>*</code>）。但我们在需要的情况下可以用 <code>columns</code> 方法修改要查询的字段集。</p>
<pre><code class=language-php>$db-&gt;users-&gt;select()
    -&gt;columns('name')
    -&gt;fetchAll();
</code></pre>
<p>你可以用 select 查询作为适当的迭代器，或者直接使用 <code>run</code> 方法，后者会返回 <code>Spiral\Database\Statement</code> 的实例：</p>
<pre><code class=language-php>foreach($select-&gt;getIterator() as $row) {
    dump($row);
}
</code></pre>
<p>如果要把所有记录作为数组返回，可以使用 <code>fetchAll</code> 方法：</p>
<pre><code class=language-php>foreach($select-&gt;fetchAll() as $row) {
    dump($row);
}
</code></pre>
<p>任何时候，如果需要的话，可以调用 <code>sqlStatement</code> 方法来查看生成的 sql 语句：</p>
<pre><code class=language-php>dump(
    $db-&gt;users-&gt;select()
        -&gt;columns('name')
        -&gt;sqlStatement()
);
</code></pre>
<h3 id=where-语句>Where 语句</h3>
<p>使用 <code>where</code>、<code>andWhere</code>、<code>orWhere</code> 可以添加 WHERE 条件：</p>
<h4 id=基础条件>基础条件</h4>
<p>我们以我们示例表中的 <code>status</code> 字段为例，添加一些简单的查询条件：</p>
<pre><code class=language-php>$select = $db-&gt;select()
    -&gt;from('test')
    -&gt;columns(['id', 'status', 'name']);

$select-&gt;where('status', '=', 'active');

foreach ($select as $row) {
    dump($row);
}
</code></pre>
<pre><code class=language-sql>SELECT
`id`, `status`, `name`
FROM `primary_test`
WHERE `status` = 'active'        
</code></pre>
<blockquote>
<p>请注意底层代码会使用 pdo 的 prepared 语句。</p>
</blockquote>
<p>简单的 <code>=</code> 操作符可以省略：</p>
<pre><code class=language-php>$select-&gt;where('status', 'active');
</code></pre>
<h4 id=where-操作符>Where 操作符</h4>
<p>第二个参数可以用来指定操作符（如果提供了三个参数）：</p>
<pre><code class=language-php>$select-&gt;where('id', '&gt;', 10);
$select-&gt;where('status', 'like', 'active');
</code></pre>
<p>如果使用 between 和 not between 操作，需要给 where 方法提供第四个参数：</p>
<pre><code class=language-php>$select-&gt;where('id', 'between', 10, 20);
</code></pre>
<p>生成的 SQL 类似这样：</p>
<pre><code class=language-sql>SELECT
`id`, `status`, `name`
FROM `primary_test`
WHERE `id` BETWEEN 10 AND 20  
</code></pre>
<h4 id=多个-where-条件>多个 Where 条件</h4>
<p>可以直接链式调用多个 where 方法：</p>
<pre><code class=language-php>$select
    -&gt;where('id', 1)
    -&gt;where('status', 'active');
</code></pre>
<p><code>andWhere</code> 方法是 <code>where</code> 的别名，所以上面的查询也可以写为下面的形式，以提升可读性：</p>
<pre><code class=language-php>$select
    -&gt;where('id', 1)
    -&gt;andWhere('status', 'active');
</code></pre>
<p>生成的 SQL 类似这样：</p>
<pre><code class=language-sql>SELECT
`id`, `status`, `name`
FROM `primary_test`
WHERE `id` = 1 AND `status` = 'active'
</code></pre>
<p>Select 查询会根据你的运算符顺序和布尔运算符生成 SQL:</p>
<pre><code class=language-php>$select
    -&gt;where('id', 1)
    -&gt;orWhere('id', 2)
    -&gt;orWhere('status', 'active');
</code></pre>
<pre><code class=language-sql>SELECT
`id`, `status`, `name`
FROM `primary_test`
WHERE `id` = 1 OR `id` = 2 OR `status` = 'active'
</code></pre>
<h4 id=复杂分组-where-条件>复杂/分组 Where 条件</h4>
<p>如果需要在使用多个 where 条件时，对它们进行分组，可以用匿名函数作为第一个参数：</p>
<pre><code class=language-php>$select
    -&gt;where('id', 1)
    -&gt;where(
        static function (SelectQuery $select) {
            $select
                -&gt;where('status', 'active')
                -&gt;orWhere('id', 10);
        }
    );
</code></pre>
<pre><code class=language-sql>SELECT
`id`, `status`, `name`
FROM `primary_test`
WHERE `id` = 1 AND (`status` = 'active' OR `id` = 10)
</code></pre>
<p>布尔操作符也是支持的：</p>
<pre><code class=language-php>$select
    -&gt;where('id', 1)
    -&gt;orWhere(
        static function (SelectQuery $select) {
            $select
                -&gt;where('status', 'active')
                -&gt;andWhere('id', 10);
        }
    );
</code></pre>
<p>生成的 SQL 语句：</p>
<pre><code class=language-sql>SELECT
`id`, `status`, `name`
FROM `primary_test`
WHERE `id` = 1 OR (`status` = 'active' AND `id` = 10)     
</code></pre>
<blockquote>
<p>你可以根据需要嵌套任意数量的查询条件。</p>
</blockquote>
<h4 id=简化数组-where-条件>简化/数组 Where 条件</h4>
<p>还可以使用
<a href=https://docs.mongodb.org/manual/reference/operator/query/ target=_blank rel=noopener>MongoDB 风格</a> 的 where 条件构造：</p>
<pre><code class=language-php>$select-&gt;where([
    'id'     =&gt; 1,
    'status' =&gt; 'active'
]);
</code></pre>
<p>这样的代码会被识别为两个 where 方法调用，并生成以下的 SQL:</p>
<pre><code class=language-sql>SELECT
`id`, `status`, `name`
FROM `primary_test`
WHERE (`id` = 1 AND `status` = 'active')
</code></pre>
<p>当然也可以用嵌套的数组来指定比较运算符：</p>
<pre><code class=language-php>$select-&gt;where([
    'id'     =&gt; ['in' =&gt; new Parameter([1, 2, 3])],
    'status' =&gt; ['like' =&gt; 'active']
]);
</code></pre>
<blockquote>
<p>请注意，必须使用 Parameter 类封装所有的数组参数，标量参数会自动封装。</p>
</blockquote>
<p>生成的 SQL:</p>
<pre><code class=language-sql>SELECT
`id`, `status`, `name`
FROM `primary_test`
WHERE (`id` IN (1, 2, 3) AND `status` LIKE 'active')
</code></pre>
<p>对单个字段使用多个条件也是支持的：</p>
<pre><code class=language-php>$select-&gt;where([
    'id' =&gt; [
        'in' =&gt; [1, 2, 3],
        '&lt;'  =&gt; 100
    ]
]);
</code></pre>
<p>在创建 where 分组的时候，可以使用 <code>@or</code> 和 <code>@and</code> 来简化分组：</p>
<pre><code class=language-php>$select
    -&gt;where(
        static function (SelectQuery $select) {
            $select
                -&gt;where('id', 'between', 10, 100)
                -&gt;andWhere('name', 'Anton');
        }
    )
    -&gt;orWhere('status', 'disabled');
</code></pre>
<p>上面的代码可以简化为：</p>
<pre><code class=language-php>$select-&gt;where([
    '@or' =&gt; [
        [
            'id'   =&gt; ['between' =&gt; [10, 100]],
            'name' =&gt; 'Anton'
        ],
        ['status' =&gt; 'disabled']
    ]
]);
</code></pre>
<p>以上两种形式的代码生成的 SQL 都一样：</p>
<pre><code class=language-sql>SELECT
`id`, `status`, `name`
FROM `primary_test`
WHERE ((`id` BETWEEN 10 AND 100 AND `name` = 'Anton') OR `status` = 'disabled')
</code></pre>
<p>你可以尝试分别用两种方法来定义 where 条件，然后选择更喜欢的一种。</p>
<h4 id=参数>参数</h4>
<p>Spiral 框架内部用 <code>Parameter</code> 类模拟所有的给定值，在某些情况下（数组）你可能需要直接传递 <code>Parameter</code> 类型。你可以执行 <code>run</code> 方法之前的任何时候改变参数的值：</p>
<pre><code class=language-php>use Spiral\Database\Injection\Parameter;
// ...

$select = $db-&gt;select()
    -&gt;from('test')
    -&gt;columns(['id', 'status', 'name']);

$select-&gt;where('id', $id = new Parameter(null));

// 绑定新的参数值
$id-&gt;setValue(15);

foreach ($select as $row) {
    dump($row);
}
</code></pre>
<blockquote>
<p>你也可以传递第二个参数用于指定该参数值的 PDO 参数类型： <code>new Parameter(1, PDO::PARAM_INT)</code>.
在框架内部，每一个传递到 <code>where</code> 方法的值默认都会使用 Parameter 类进行封装。</p>
</blockquote>
<p>如果你想自行定义你的参数包装逻辑，可以实现 <code>ParameterInterface</code> 接口。</p>
<h4 id=sql-片段和表达式>SQL 片段和表达式</h4>
<p>查询构造器允许你使用自定义的 SQL 代码或者表达式替换一些 where 语句。<code>Spiral\Database\Injections\Fragment</code> 和 <code>Spiral\Database\Injections\Expression</code> 就是用于这种需求的。</p>
<p>例如，用片段（Fragment）将原生SQL代码绕过转义添加到查询中：</p>
<pre><code class=language-php>use Spiral\Database\Injection\Fragment;

// 255
$select-&gt;where('id', '=', new Fragment(&quot;DAYOFYEAR('2015-09-12')&quot;));
</code></pre>
<pre><code class=language-sql>SELECT
`id`, `status`, `name`
FROM `primary_test`
WHERE `id` = DAYOFYEAR('2015-09-12')
</code></pre>
<p>如果希望将复杂的值与用户参数进行比较，则可以用表达式（Expression）替换 where 参数中的字段：</p>
<pre><code class=language-php>use Spiral\Database\Injection\Expression;

$select-&gt;where(
    new Expression(&quot;DAYOFYEAR(concat('2015-09-', id))&quot;), 
    '=',
    255
);
</code></pre>
<pre><code class=language-sql>SELECT
*
FROM `x_users`
WHERE DAYOFYEAR(concat('2015-09-', `id`)) = 255
</code></pre>
<blockquote>
<p>请注意，表示式中所有的字段标识都会被自动加引号。</p>
</blockquote>
<p>连接多个字段的方法也是一样：</p>
<pre><code class=language-php>$select-&gt;where(new Expression(&quot;CONCAT(id, '-', status)&quot;), '1-active');
</code></pre>
<pre><code class=language-sql>SELECT
`id`, `status`, `name`
FROM `primary_test`
WHERE CONCAT(`id`, '-', `status`) = '1-active'
</code></pre>
<p>如果数据库连接指定了表前缀，表达式中的表名称会被自动处理：</p>
<pre><code class=language-php>$select-&gt;where(
    new Expression(&quot;CONCAT(test.id, '-', test.status)&quot;), 
    '1-active'
);
</code></pre>
<pre><code class=language-sql>SELECT
`id`, `status`, `name`
FROM `primary_test`
WHERE CONCAT(`primary_test`.`id`, '-', `primary_test`.`status`) = '1-active'
</code></pre>
<p>你也可以在插入和更新语句中使用表达式和片段作为字段值。</p>
<blockquote>
<p>安全提示：请尽可能不要在片段或者表达式中使用客户输入数据。</p>
</blockquote>
<h3 id=表和字段别名>表和字段别名</h3>
<p>查询构造器支持用户定义的表和字段别名：</p>
<pre><code class=language-php>$select = $db-&gt;select()
    -&gt;from('test as abc')
    -&gt;columns([
        'id',
        'status',
        'name'
    ]);

$select-&gt;where('abc.id', '&gt;', 10);

foreach ($select as $row) {
    dump($row);
}
</code></pre>
<pre><code class=language-sql>SELECT
`id`, `status`, `name`
FROM `primary_test` as `abc`
WHERE `abc`.`id` &gt; 10
</code></pre>
<p>字段别名：</p>
<pre><code class=language-php>$select = $db-&gt;select()
    -&gt;from('test')
    -&gt;columns([
        'id',
        'status as st',
        'name',
        &quot;CONCAT(test.name, ' ', test.status) as name_and_status&quot;
    ]);

foreach ($select as $row) {
    dump($row);
}
</code></pre>
<p>生成的 SQL:</p>
<pre><code class=language-sql>SELECT
    `id`, 
    `status` as `st`, 
    `name`, 
    CONCAT(`primary_test`.`name`, ' ',`primary_test`.`status`) as `name_and_status`
FROM `primary_test`
</code></pre>
<h4 id=子查询和嵌套查询>子查询和嵌套查询</h4>
<p>Spiral 的每个查询构造器都是实现了 <code>FragmentInterface</code> 接口的实例，因此在你需要复杂的嵌套查询时，有能力使用它们：</p>
<pre><code class=language-php>$select = $db-&gt;select()
    -&gt;from('test')
    -&gt;columns(['id', 'status', 'name']);

$select-&gt;where(
    'id',
    'IN',
    $database-&gt;select('id')
        -&gt;from('test')
        -&gt;where('id', 'BETWEEN', 10, 100)
);

foreach ($select as $row) {
    dump($row);
}
</code></pre>
<pre><code class=language-sql>SELECT
`id`, `status`, `name`
FROM `primary_test`
WHERE `id` IN  (SELECT
`id`
FROM `primary_test`
WHERE `id` BETWEEN 10 AND 100)  
</code></pre>
<p>你还可以在 where 语句中使用嵌套查询的返回值：</p>
<pre><code class=language-php>$select-&gt;where(
    $db-&gt;select('COUNT(*)')
        -&gt;from('test')
        -&gt;where('id', 'BETWEEN', 10, 100), 
    '&gt;',
    1
);
</code></pre>
<pre><code class=language-sql>SELECT
`id`, `status`, `name`
FROM `primary_test`
WHERE (SELECT
COUNT(*)
FROM `primary_test`
WHERE `id` BETWEEN 10 AND 100) &gt; 1   
</code></pre>
<p>你也可以使用 <code>Expression</code> 类在父查询和子查询中交换字段标识：</p>
<pre><code class=language-php>$select = $db-&gt;select()
    -&gt;from('test')
    -&gt;columns(['id', 'status', 'name']);

$select-&gt;where(
    $db-&gt;select('name')
        -&gt;from('users')
        -&gt;where('id', '=', new Expression('test.id'))
        -&gt;where('id', '!=', 100),
    'Anton'
);
</code></pre>
<pre><code class=language-sql>SELECT
`id`, `status`, `name`
FROM `primary_test`
WHERE (SELECT
`name`
FROM `primary_users`
WHERE `id` = `primary_test`.`id` AND `id` != 100) = 'Anton'
</code></pre>
<blockquote>
<p>嵌套查询只有在嵌套查询与主建库属于同一个数据库时才可用。</p>
</blockquote>
<h3 id=having>Having</h3>
<p>使用 <code>having</code>、<code>orhaving</code> 和 <code>andHaving</code> 方法来定义 HAVING 条件。使用方法与 WHERE 语句基本一致。</p>
<h3 id=联合查询>联合查询</h3>
<p>你可以使用 <code>leftJoin</code>、<code>join</code>、<code>rightJoin</code>、<code>fullJoin</code> 和 <code>innerJoin</code> 方法将任何需要的数据表加入到查询中：</p>
<pre><code class=language-php>$select = $db-&gt;table('test')
    -&gt;select(['test.*', 'u.name as u']);

$select-&gt;leftJoin('users', 'u')
    -&gt;on('users.id', 'test.id');
</code></pre>
<pre><code class=language-sql> SELECT
`x_test`.*, `u`.`name` AS `u`
FROM `x_test` 
LEFT JOIN `x_users` AS `u`
    ON `x_users`.`id` = `x_test`.`id`
</code></pre>
<p>联合查询中的 <code>on</code> 方法工作原理与 <code>where</code> 完全相同，只是将提供的值作为标识符而不是参数值。把 <code>on</code>、<code>andOn</code> 和 <code>orOn</code> 方法串联起来可以创建更加复杂的连接。</p>
<pre><code class=language-php>$select-&gt;leftJoin('users')
    -&gt;on('users.id', 'test.id')
    -&gt;orOn('users.id', 'test.balance');
</code></pre>
<p>数组形式的 where 条件也同样支持：</p>
<pre><code class=language-sql>$select-&gt;leftJoin('users', 'u')-&gt;on([
    '@or' =&gt; [
        ['u.id' =&gt; 'test.id'],
        ['u.id' =&gt; 'test.balance']
    ]
]);
</code></pre>
<p>生成的 SQL:</p>
<pre><code class=language-sql>SELECT
`primary_test`.*, `primary_users`.`name` as `user_name`
FROM `primary_test`  
LEFT JOIN `primary_users`
    ON (`primary_users`.`id` = `primary_test`.`id` OR `primary_users`.`id` = `primary_test`.`balance`)    
</code></pre>
<h4 id=on-where-语句>On Where 语句</h4>
<p>要在 ON 语句中包含用户输入值，可以使用 <code>onWhere</code>, <code>orOnWhere</code> 和 <code>andOnWhere</code>:</p>
<pre><code class=language-php>$select
    -&gt;innerJoin('users')
    -&gt;on(['users.id' =&gt; 'test.id'])
    -&gt;onWhere('users.name', 'Anton');
</code></pre>
<pre><code class=language-sql>SELECT
`primary_test`.*, `primary_users`.`name` as `user_name`
FROM `primary_test`  
INNER JOIN `primary_users`
    ON `primary_users`.`id` = `primary_test`.`id` AND `primary_users`.`name` = 'Anton'
</code></pre>
<h4 id=别名>别名</h4>
<p>联合查询方法中的第二个参数用于定义表的别名，可以在查询的 <code>on</code> 和 <code>where</code> 语句中使用：</p>
<pre><code class=language-php>$select = $db-&gt;table('test')
    -&gt;select(['test.*', 'uu.name as user_name'])
    -&gt;innerJoin('users', 'uu')
    -&gt;onWhere('uu.name', 'Anton');
</code></pre>
<p>第二种写法：</p>
<pre><code class=language-php>$select = $db-&gt;table('test')
    -&gt;select(['test.*', 'uu.name as user_name'])
    -&gt;innerJoin('users as uu')
    -&gt;onWhere('uu.name', 'Anton');
</code></pre>
<pre><code class=language-sql>SELECT
`primary_test`.*, `uu`.`name` as `user_name`
FROM `primary_test`  
INNER JOIN `primary_users` as `uu`
    ON `uu`.`id` = `primary_test`.`id` AND `uu`.`name` = 'Anton'       
</code></pre>
<h3 id=排序>排序</h3>
<p>使用 <code>orderBy</code> 来指定结果排序：</p>
<pre><code class=language-php>// 我们的查询中有联合查询，因此表名是必须的。
$select
    -&gt;orderBy('test.id', SelectQuery::SORT_DESC);
</code></pre>
<p>组合使用多个 <code>orderBy</code> 是可以的：</p>
<pre><code class=language-php>$select
    -&gt;orderBy(
        'test.name', SelectQuery::SORT_DESC
    )-&gt;orderBy(
        'test.id', SelectQuery::SORT_ASC
    );
</code></pre>
<p>另一种写法：</p>
<pre><code class=language-php>$select
    -&gt;orderBy([
        'test.name' =&gt; SelectQuery::SORT_DESC,
        'test.id'   =&gt; SelectQuery::SORT_ASC
    ]); 
</code></pre>
<p>两种写法生成的 SQL 都一样：</p>
<pre><code class=language-sql>SELECT
`primary_test`.*, `uu`.`name` as `user_name`
FROM `primary_test`  
INNER JOIN `primary_users` as `uu`
    ON `uu`.`id` = `primary_test`.`id` AND `uu`.`name` = 'Anton' 
ORDER BY `primary_test`.`name` DESC, `primary_test`.`id` ASC
</code></pre>
<blockquote>
<p>你也可以使用片段（Fragment）代替排序标识符（默认情况下排序标识符会作为字段名或者表达式来处理）。</p>
</blockquote>
<h3 id=分组和去重>分组和去重</h3>
<p>如果你希望对查询结果进行去重，可以使用 <code>distinct</code> 方法（在 ORM 中加载 HAS_MANY/MANY_TO_MANY 关系时总是使用 <code>distinct</code>）。</p>
<pre><code class=language-php>$select-&gt;distinct();
</code></pre>
<p>结果分组的操作通过 <code>groupBy</code> 方法来实现：</p>
<pre><code class=language-php>$select = $db-&gt;table('test')
    -&gt;select(['status', 'count(*) as count'])
    -&gt;groupBy('status');
</code></pre>
<p>上面的代码会生成以下 SQL 语句：</p>
<pre><code class=language-sql>SELECT
`status`, count(*) as `count`
FROM `primary_test`
GROUP BY `status`
</code></pre>
<h3 id=聚合和计数>聚合和计数</h3>
<p>由于可以用 COUNT 和其它聚合函数来操作查询的字段，所以你构造的查询看起来可能会像这样：</p>
<pre><code class=language-php>$select = $db-&gt;table('test')-&gt;select(['COUNT(*)']);
</code></pre>
<p>然而，在很多情况下你可能想直接获得计数或者汇总结果但不要进行列操作。这种情况下可以使用 <code>count</code>、<code>avg</code>、<code>sum</code>、<code>max</code> 和 <code>min</code> 方法：</p>
<pre><code class=language-php>$select = $db-&gt;table('test')
    -&gt;select(['id', 'name', 'status']);

dump($select-&gt;count());
dump($select-&gt;sum('balance'));
</code></pre>
<pre><code class=language-sql>SELECT
COUNT(*)
FROM `primary_test`;

SELECT
SUM(`balance`)
FROM `primary_test`;
</code></pre>
<h3 id=分页>分页</h3>
<p>要对查询结果进行分页，可以使用 <code>limit</code> 和 <code>offset</code> 方法：</p>
<pre><code class=language-php>$select = $db-&gt;table('test')
    -&gt;select(['id', 'name', 'status'])
    -&gt;limit(10)
    -&gt;offset(1);

foreach ($select as $row) {
    dump($row);
}
</code></pre>
<h2 id=更新查询构造器>更新查询构造器</h2>
<p>使用数据库连接实例或者表实例的 <code>update</code> 方法来获得更新查询构造器，然后调用该构造器的 <code>run</code> 方法对查询结果进行更新操作：</p>
<pre><code class=language-php>$update = $db-&gt;table('test')
    -&gt;update(['name' =&gt; 'Abc'])
    -&gt;where('id', '&lt;', 10)
    -&gt;run();
</code></pre>
<pre><code class=language-sql>UPDATE `primary_test`
SET `name` = 'Abc'
WHERE `id` &lt; 10
</code></pre>
<p>可以使用 <code>Expression</code> 和 <code>Fragment</code> 的实例作为更新的值：</p>
<pre><code class=language-php>$update = $db-&gt;table('test')
    -&gt;update([
        'name' =&gt; new Expression('UPPER(test.name)')
    ])
    -&gt;where('id', '&lt;', 10)
    -&gt;run();
</code></pre>
<pre><code class=language-sql>UPDATE `primary_test`
SET `name` = UPPER(`primary_test`.`name`)
WHERE `id` &lt; 10
</code></pre>
<p>嵌套查询在更新操作中同样支持：</p>
<pre><code class=language-php>$update = $db-&gt;table('test')
    -&gt;update([
        'name' =&gt; $database
            -&gt;table('users')
            -&gt;select('name')
            -&gt;where('id', 1)
    ])
    -&gt;where('id', '&lt;', 10)-&gt;run();
</code></pre>
<pre><code class=language-sql>UPDATE `primary_test`
SET `name` = (SELECT
`name`
FROM `primary_users`
WHERE `id` = 1)
WHERE `id` &lt; 10 
</code></pre>
<blockquote>
<p>更新查询中的 where 方法与 Select 查询中的 where 方法工作原理完全一致。</p>
</blockquote>
<h2 id=删除查询构造器>删除查询构造器</h2>
<p>删除查询通过 <code>delete</code> 方法获取：</p>
<pre><code class=language-php>$db-&gt;table('test')
    -&gt;delete()
    -&gt;where('id', '&lt;', 1000)
    -&gt;run();
</code></pre>
<p>你也可以在数据表实例的 <code>delete</code> 方法中直接以数组形式提供 where 条件：</p>
<pre><code class=language-php>$db-&gt;table('test')
    -&gt;delete([
        'id' =&gt; ['&gt;' =&gt; 1000]
    ])
    -&gt;run();
</code></pre>
<h2 id=复杂表达式>复杂表达式</h2>
<p>你可以使用 Expression 对象来创建复杂的、特定于某种数据库的、包含参数的 SQL 语句注入查询中：</p>
<pre><code class=language-php>$db-&gt;table('test')
    -&gt;select()
    -&gt;where(new Expression('SUM(column) = ?', $value))
    -&gt;run();
</code></pre>
</div>
<div class=article-widget>
<div class=post-nav>
<div class=post-nav-item>
<div class=meta-nav>上一页</div>
<a href=/docs/http/session/ rel=next>Session</a>
</div>
<div class=post-nav-item>
<div class=meta-nav>下一页</div>
<a href=/docs/http/cookies/ rel=prev>Cookies</a>
</div>
</div>
</div>
</div>
<div class=body-footer>
<p>最近更新于 2020-08-28</p>
<p class=edit-page>
<a href=https://github.com/krwu/spiraldocs/edit/feat/chinese/zh_CN/database/query-builders.md>
<i class="fas fa-pen pr-2"></i>编辑本页
</a>
</p>
</div>
</article>
<footer class=site-footer>
<p class=powered-by><span class=copyright>© 2019 - 2021 <a href=https://studyspiral.cn/>StudySpiral</a> All rights reserved.</span>
</p>
<p class=powered-by>
<a href=http://www.beian.miit.gov.cn/ target=_blank rel="noopener noreferer">粤ICP备14011364号</a>
<a href="http://www.beian.gov.cn/portal/registerSystemInfo?recordcode=44030402001866" target=_blank rel="noopener noreferer"><img style=display:inline-block src=/img/gaba.png>粤公网安备 44030402001866号</a>
</p>
<p id=webify class=powered-by style=display:none>[<a href=https://webify.cloudbase.net/ target=_blank rel=noopener>CloudBase Webify</a>] 提供网站托管服务</p>
<script async defer>window.addEventListener('DOMContentLoaded',()=>{const{host:a}=window.location;a.toLocaleLowerCase()==='docs.studyspiral.cn'&&(document.getElementById('webify').style.display='block')})</script>
</footer>
</main>
</div>
</div>
<script src=https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin=anonymous></script>
<script src=https://cdnjs.cloudflare.com/ajax/libs/jquery.imagesloaded/4.1.4/imagesloaded.pkgd.min.js integrity="sha256-lqvxZrPLtfffUl2G/e7szqSvPBILGbwmsGE1MKlOi0Q=" crossorigin=anonymous></script>
<script src=https://cdnjs.cloudflare.com/ajax/libs/jquery.isotope/3.0.6/isotope.pkgd.min.js integrity="sha256-CBrpuqrMhXwcLLUd5tvQ4euBHCdh7wGlDfNz8vbu/iI=" crossorigin=anonymous></script>
<script src=https://cdnjs.cloudflare.com/ajax/libs/fancybox/3.5.7/jquery.fancybox.min.js integrity="sha256-yt2kYMy0w8AbtF89WXb2P1rfjcP/HTHLT7097U8Y5b8=" crossorigin=anonymous></script>
<script src=https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.18.1/highlight.min.js integrity="sha256-eOgo0OtLL4cdq7RdwRUiGKLX9XsIJ7nGhWEKbohmVAQ=" crossorigin=anonymous></script>
<script src=https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.18.1/languages/go.min.js></script>
<script>const code_highlighting=!0</script>
<script>const isSiteThemeDark=!1</script>
<script>const search_config={indexURI:"/index.json",minLength:1,threshold:.3},i18n={no_results:"没有找到结果",placeholder:"搜索...",results:"搜索结果"},content_type={post:"文章",project:"项目",publication:"出版物",talk:"演讲"}</script>
<script src=https://cdnjs.cloudflare.com/ajax/libs/anchor-js/4.1.1/anchor.min.js integrity="sha256-pB/deHc9CGfFpJRjC43imB29Rse8tak+5eXqntO94ck=" crossorigin=anonymous></script>
<script>anchors.add()</script>
<script id=search-hit-fuse-template type=text/x-template>
      <div class="search-hit" id="summary-{{key}}">
      <div class="search-hit-content">
        <div class="search-hit-name">
          <a href="{{relpermalink}}">{{title}}</a>
          <div class="article-metadata search-hit-type">{{type}}</div>
          <p class="search-hit-description">{{snippet}}</p>
        </div>
      </div>
      </div>
    </script>
<script src=https://cdnjs.cloudflare.com/ajax/libs/fuse.js/3.2.1/fuse.min.js integrity="sha256-VzgmKYmhsGNNN4Ph1kMW+BjoYJM2jV5i4IlFoeZA9XI=" crossorigin=anonymous></script>
<script src=https://cdnjs.cloudflare.com/ajax/libs/mark.js/8.11.1/jquery.mark.min.js integrity="sha256-4HLtjeVgH0eIB3aZ9mLYF6E8oU5chNdjU6p6rrXpl9U=" crossorigin=anonymous></script>
<script src=/js/academic.min.6f1005d1a84220e2f466ff3d8e712f31.js></script>
<div id=modal class="modal fade" role=dialog>
<div class=modal-dialog>
<div class=modal-content>
<div class=modal-header>
<h5 class=modal-title>引用</h5>
<button type=button class=close data-dismiss=modal aria-label=Close>
<span aria-hidden=true>&#215;</span>
</button>
</div>
<div class=modal-body>
<pre><code class="tex hljs"></code></pre>
</div>
<div class=modal-footer>
<a class="btn btn-outline-primary my-1 js-copy-cite" href=# target=_blank>
<i class="fas fa-copy"></i> 复制
</a>
<a class="btn btn-outline-primary my-1 js-download-cite" href=# target=_blank>
<i class="fas fa-download"></i> 下载
</a>
<div id=modal-error></div>
</div>
</div>
</div>
</div>
</body>
</html>